package org.jeecg.modules.wechat.service.impl;/*
 *
 *改了七八遍 照顾找包困难的朋友吧
 *
 */

import cn.hutool.core.text.StrFormatter;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.util.StringUtils;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.nurse_user.entity.NurseUser;
import org.jeecg.modules.nurse_user.service.INurseUserService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.wechat.constants.WXPayConstants;
import org.jeecg.modules.wechat.service.WechatPaymentService;
import org.jeecg.modules.wechat.utils.SendSmsUtil;
import org.jeecg.modules.wechat.utils.WXPaySignatureCertificateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Slf4j
@Service
public class WeChatPaymentServiceImpl implements WechatPaymentService {

    //平台证书序列号
    @Value("${wechat.nurse.mchserialno:}")
    private String mchSerialNo;

    @Value("${wechat.nurse.mchserialnoah:}")
    private String mchSerialNoah;
    //appID
    @Value("${wechat.nurse.appid:}")
    private String APP_ID;

    //商户id
    @Value("${wechat.nurse.mchid:}")
    private String Mch_ID;
    //商户id
    @Value("${wechat.nurse.mchidah:}")
    private String Mch_IDah;

    // API V3密钥
    @Value("${wechat.nurse.apiv3key:}")
    private String apiV3Key;
    // API V3密钥
    @Value("${wechat.nurse.apiv3keyah:}")
    private String apiV3Keyah;

    @Value("${wechat.nurse.pay-notify-url:}")
    private String PAY_NOTIFY_URL;

    @Value("${wechat.nurse.pay-notify-url-medication:}")
    private String PAY_NOTIFY_URL_MEDICATION;

    @Value("${wechat.nurse.pay-notify-url-news:}")
    private String PAY_NOTIFY_URL_NEWS;

    @Value("${wechat.nurse.pay-notify-url-video:}")
    private String PAY_NOTIFY_URL_VIDEO;
    @Value("${wechat.nurse.pay-notify-urlah:}")
    private String PAY_NOTIFY_URLAH;

    @Value("${wechat.nurse.pay-notify-url-medicationah:}")
    private String PAY_NOTIFY_URL_MEDICATIONAH;

    @Value("${wechat.nurse.pay-notify-url-newsah:}")
    private String PAY_NOTIFY_URL_NEWSAH;

    @Value("${wechat.nurse.pay-notify-url-videoah:}")
    private String PAY_NOTIFY_URL_VIDEOAH;

    @Value("${wechat.nurse.refund-notify-url:}")
    private String REFUND_NOTIFY_URL;

    @Value("${wechat.nurse.refund-notify-url-medication:}")
    private String REFUND_NOTIFY_URL_MEDICATION;

    @Value("${wechat.nurse.refund-notify-urlah-medication:}")
    private String REFUND_NOTIFY_URL_MEDICATIONah;

    @Value("${wechat.nurse.refund-notify-urlah:}")
    private String REFUND_NOTIFY_URLah;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private INurseUserService nurseUserService;

    @Autowired
    private ISysUserService sysUserService;



    // 验证码有效期（分钟）
    private final int EXPIRE_MINUTES = 5;
    // 防刷间隔（分钟）
    private final int ANTI_SPAM_MINUTES = 1;

    /**
     * V3微信支付统一下单
     *
     * @param payParam
     * @return
     */
    @Override
    public BaseMap weChatDoUnifiedOrder(BaseMap payParam) {
        return weChatDoUnifiedOrder(payParam, null);
    }
    
    /**
     * V3微信支付统一下单（指定商户）
     *
     * @param payParam
     * @param mchId 商户号
     * @return
     */
    @Override
    public BaseMap weChatDoUnifiedOrder(BaseMap payParam, String mchId) {
        payParam.put("code", 400);
        try {
            // 根据商户号选择配置
            String merchantId = Mch_ID;
            String merchantSerialNo = mchSerialNo;
            String merchantApiV3Key = apiV3Key;
            String pay_notify_url=PAY_NOTIFY_URL;
            String pay_notify_url_medication=PAY_NOTIFY_URL_MEDICATION;
            String pay_notify_url_news=PAY_NOTIFY_URL_NEWS;
            String pay_notify_url_video=PAY_NOTIFY_URL_VIDEO;
            
            // 如果传入了商户号，则根据商户号选择配置
            if (mchId != null && !mchId.isEmpty()) {
                if (mchId.equals(Mch_IDah)) {
                    merchantId = Mch_IDah;
                    merchantSerialNo = mchSerialNoah;
                    merchantApiV3Key = apiV3Keyah;
                    pay_notify_url=PAY_NOTIFY_URLAH;
                    pay_notify_url_medication=PAY_NOTIFY_URL_MEDICATIONAH;
                    pay_notify_url_news=PAY_NOTIFY_URL_NEWSAH;
                    pay_notify_url_video=PAY_NOTIFY_URL_VIDEOAH;
                } else if (mchId.equals(Mch_ID)) {
                    merchantId = Mch_ID;
                    merchantSerialNo = mchSerialNo;
                    merchantApiV3Key = apiV3Key;
                    pay_notify_url=PAY_NOTIFY_URL;
                    pay_notify_url_medication=PAY_NOTIFY_URL_MEDICATION;
                    pay_notify_url_news=PAY_NOTIFY_URL_NEWS;
                    pay_notify_url_video=PAY_NOTIFY_URL_VIDEO;
                }
            }

            //验证证书
            CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(merchantSerialNo, merchantId, merchantApiV3Key);

            //app下单
            HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API + WXPayConstants.PAY_TRANSACTIONS_JSAPI);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid", merchantId)
                    .put("appid", APP_ID)
                    .put("description", payParam.get("description").toString())
                    .put("notify_url", pay_notify_url)//回调
                    .put("out_trade_no", payParam.get("out_trade_no").toString());
            rootNode.putObject("amount")
                    .put("total", payParam.getLong("total"));
            rootNode.putObject("payer")
                    .put("openid", payParam.get("openid").toString());
          if("1".equals(payParam.get("type")))  rootNode.put("notify_url", pay_notify_url_medication);//回调
          else if("2".equals(payParam.get("type")))rootNode.put("notify_url", pay_notify_url_news);//回调
          else if("3".equals(payParam.get("type")))rootNode.put("notify_url", pay_notify_url_video);//回调
            objectMapper.writeValue(bos, rootNode);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            //获取返回状态
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) { //处理成功

                String result = EntityUtils.toString(response.getEntity(), "UTF-8");

                JSONObject object = JSONObject.parseObject(result);
                //获取预付单
                String prepayId = object.getString("prepay_id");

                payParam.put("prepayid", prepayId);
                payParam.put("mchId", mchId);
                payParam = WXPaySignatureCertificateUtil.jsApiPay(payParam, APP_ID);
                payParam.put("code", 200);
                payParam.put("message", "下单成功");
                return payParam;
            }
            payParam.put("code", 400);
            payParam.put("message", "下单失败");
            payParam.put("data", EntityUtils.toString(response.getEntity(), "UTF-8"));
            return payParam;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return payParam;
    }


    /**
     * 微信支付回调通知
     *
     * @return
     */
    @Override
    public BaseMap weChatNotificationHandler(HttpServletRequest request,String mchid) {
        BaseMap map = new BaseMap();
        String merchantId = Mch_IDah;
        String merchantSerialNo = mchSerialNoah;
        String merchantApiV3Key = apiV3Keyah;
        if (mchid != null && !mchid.isEmpty()) {
            if (mchid.equals(Mch_IDah)) {
                merchantId = Mch_IDah;
                merchantSerialNo = mchSerialNoah;
                merchantApiV3Key = apiV3Keyah;
            } else if (mchid.equals(Mch_ID)) {
                merchantId = Mch_ID;
                merchantSerialNo = mchSerialNo;
                merchantApiV3Key = apiV3Key;
            }
        }


        try {
            BufferedReader br = request.getReader();
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            // 构建request，传入必要参数
            NotificationRequest requests = new NotificationRequest.Builder()
                    .withSerialNumber(request.getHeader("Wechatpay-Serial"))
                    .withNonce(request.getHeader("Wechatpay-Nonce"))
                    .withTimestamp(request.getHeader("Wechatpay-Timestamp"))
                    .withSignature(request.getHeader("Wechatpay-Signature"))
                    .withBody(String.valueOf(sb))
                    .build();
            //验签
            NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifiers(merchantSerialNo, merchantId, merchantApiV3Key), merchantApiV3Key.getBytes(StandardCharsets.UTF_8));
            //解析请求体
            Notification notification = handler.parse(requests);

            String decryptData = notification.getDecryptData();
            //解析
            JSONObject jsonObject = JSONObject.parseObject(decryptData);
            //支付状态交易状态，枚举值： SUCCESS：支付成功 REFUND：转入退款 NOTPAY：未支付 CLOSED：已关闭 REVOKED：已撤销（付款码支付）
            // USERPAYING：用户支付中（付款码支付） PAYERROR：支付失败(其他原因，如银行返回失败)
            String trade_state = jsonObject.getString("trade_state");
            if (trade_state.equals("SUCCESS")) {
                //订单号
                String out_trade_no = jsonObject.getString("out_trade_no");
                //此处处理业务
                map.put("out_trade_no", out_trade_no);
                map.put("code", 200);
                map.put("message", "成功");
                //消息推送成功
                return map;
            }
            map.put("code", "RESOURCE_NOT_EXISTS");
            map.put("message", "订单不存在");
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put("code", "FAIL");
        map.put("message", "失败");
        return map;
    }

    /**
     * 关闭订单
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public BaseMap closeOrder(String outTradeNo) {
        return closeOrder(outTradeNo, null);
    }
    
    /**
     * 关闭订单（指定商户）
     *
     * @param outTradeNo 订单号
     * @param mchId 商户号
     * @return
     */
    @Override
    public BaseMap closeOrder(String outTradeNo, String mchId) {
        BaseMap map = new BaseMap();
        try {
            // 根据商户号选择配置
            String merchantId = Mch_ID;
            String merchantSerialNo = mchSerialNo;
            String merchantApiV3Key = apiV3Key;
            
            // 如果传入了商户号，则根据商户号选择配置
            if (mchId != null && !mchId.isEmpty()) {
                if (mchId.equals(Mch_IDah)) {
                    merchantId = Mch_IDah;
                    merchantSerialNo = mchSerialNoah;
                    merchantApiV3Key = apiV3Keyah;
                } else if (!mchId.equals(Mch_ID)) {
                    throw new IllegalArgumentException("不支持的商户号: " + mchId);
                }
            }
            
            //验证证书
            CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(merchantSerialNo, merchantId, merchantApiV3Key);
            //关闭订单
            String url = StrFormatter.format(WXPayConstants.DOMAIN_API + WXPayConstants.PAY_TRANSACTIONS_OUT_TRADE_NO_CLOSE, outTradeNo);
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //2.添加商户id
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid", merchantId);
            objectMapper.writeValue(bos, rootNode);
            //3.调起微信关单接口
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
//            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
//            log.info("result:{}", result);
//            System.out.println(response.getStatusLine().getStatusCode() == 204);
            //无数据（Http状态码为204） 微信返回结果无数据 状态码为204 成功
            if (response.getStatusLine().getStatusCode() == 204) {
                //code 退款码请前往微信支付文档查询
                map.put("code", 200);
                map.put("message", "关闭订单成功！");
                return map;
            }
            map.put("code", 400);
            map.put("message", response);
            return map;
        } catch (Exception e) {
            log.error("关单失败:" + outTradeNo + e);
        }
        return map;
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public BaseMap queryOrder(String outTradeNo) {
        return queryOrder(outTradeNo, null);
    }
    
    /**
     * 查询订单（指定商户）
     *
     * @param outTradeNo 订单号
     * @param mchId 商户号
     * @return
     */
    @Override
    public BaseMap queryOrder(String outTradeNo, String mchId) {
        BaseMap map = new BaseMap();
        map.put("code", 400);
        try {
            // 根据商户号选择配置
            String merchantId = Mch_ID;
            String merchantSerialNo = mchSerialNo;
            String merchantApiV3Key = apiV3Key;
            
            // 如果传入了商户号，则根据商户号选择配置
            if (mchId != null && !mchId.isEmpty()) {
                if (mchId.equals(Mch_IDah)) {
                    merchantId = Mch_IDah;
                    merchantSerialNo = mchSerialNoah;
                    merchantApiV3Key = apiV3Keyah;
                } else if (!mchId.equals(Mch_ID)) {
                    throw new IllegalArgumentException("不支持的商户号: " + mchId);
                }
            }
            
            //验证证书
            CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(merchantSerialNo, merchantId, merchantApiV3Key);
            //关闭订单
            String url = StrFormatter.format(WXPayConstants.DOMAIN_API + WXPayConstants.PAY_TRANSACTIONS_OUT_TRADE_NO_QUERY, outTradeNo, merchantId);
            log.info("url:{}", url);
            HttpGet httpGet = new HttpGet(url);
            httpGet.addHeader("Accept", "application/json");
            httpGet.addHeader("Content-type", "application/json; charset=utf-8");

            CloseableHttpResponse response = httpClient.execute(httpGet);

            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                JSONObject object = JSONObject.parseObject(result);

                map.put("code", 200);
                map.put("trade_state", object.get("trade_state"));
                map.put("trade_state_desc", object.get("trade_state_desc"));
                return map;
            }
            map.put("code", 400);
            map.put("message", response);
            return map;
        } catch (Exception e) {
            log.error("查询订单失败:" + outTradeNo + e);
        }
        return map;
    }

    /**
     * 微信退款
     *
     * @param map
     * @return
     */
    @Override
    public BaseMap weChatRefunds(BaseMap map) {
        return weChatRefunds(map, null);
    }
    
    /**
     * 微信退款（指定商户）
     *
     * @param map
     * @param mchId 商户号
     * @return
     */
    @Override
    public BaseMap weChatRefunds(BaseMap map, String mchId) {
        map.put("code", 400);
//        JSONObject jsonObject = new JSONObject();


        try {
            // 根据商户号选择配置
            String merchantId = Mch_ID;
            String merchantSerialNo = mchSerialNo;
            String merchantApiV3Key = apiV3Key;
            String refundNotifyUrl = REFUND_NOTIFY_URL;
            if("medication".equals(map.get("type"))){
                refundNotifyUrl = REFUND_NOTIFY_URL_MEDICATION;
            }
            
            // 如果传入了商户号，则根据商户号选择配置
            if (mchId != null && !mchId.isEmpty()) {
                if (mchId.equals(Mch_IDah)) {
                    merchantId = Mch_IDah;
                    merchantSerialNo = mchSerialNoah;
                    merchantApiV3Key = apiV3Keyah;
                    refundNotifyUrl =  REFUND_NOTIFY_URLah;
                    if("medication".equals(map.get("type"))){
                        refundNotifyUrl = REFUND_NOTIFY_URL_MEDICATIONah;
                    }
                }
            }
            
            //验证证书
            CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign(merchantSerialNo, merchantId, merchantApiV3Key);
            //申请退款接口
            HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API + WXPayConstants.REFUND_DOMESTIC_REFUNDS);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            //微信支付订单号
            rootNode.put("out_trade_no", map.get("out_trade_no").toString())
                    .put("out_refund_no", map.get("out_refund_no").toString())
                    .put("notify_url", refundNotifyUrl);
            //退款金额
            rootNode.putObject("amount")
                    .put("refund", map.getLong("total"))
                    .put("total", map.getLong("total"))
                    .put("currency", "CNY");
            objectMapper.writeValue(bos, rootNode);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            //退款成功返回消息
            String bodyAsString = EntityUtils.toString(response.getEntity());

            JSONObject jsonObject = JSONObject.parseObject(bodyAsString);

            if (statusCode == 200 && (jsonObject.get("status").equals("SUCCESS") || jsonObject.get("status").equals("PROCESSING"))) {
                //code返回
                map.put("code", 200);
                map.put("message", "申请退款成功");
                return map;
            }
            map.put("code", 400);
            map.put("message", "申请退款失败,错误码:" + statusCode);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 申请退款回调
     *
     * @param request
     * @return
     */
    @Override
    public BaseMap weChatPayRefundsNotify(HttpServletRequest request,String mchid) {
        BaseMap map = new BaseMap();

        // 根据商户号选择配置
        String merchantId = Mch_ID;
        String merchantSerialNo = mchSerialNo;
        String merchantApiV3Key = apiV3Key;

        // 如果传入了商户号，则根据商户号选择配置
        if (mchid != null && !mchid.isEmpty()) {
            if (mchid.equals(Mch_IDah)) {
                merchantId = Mch_IDah;
                merchantSerialNo = mchSerialNoah;
                merchantApiV3Key = apiV3Keyah;
            }
        }

        try {
            BufferedReader br = request.getReader();
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            // 构建request，传入必要参数
            NotificationRequest requests = new NotificationRequest.Builder()
                    .withSerialNumber(request.getHeader("Wechatpay-Serial"))
                    .withNonce(request.getHeader("Wechatpay-Nonce"))
                    .withTimestamp(request.getHeader("Wechatpay-Timestamp"))
                    .withSignature(request.getHeader("Wechatpay-Signature"))
                    .withBody(String.valueOf(sb))
                    .build();
            //验签
            NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifiers(merchantSerialNo, merchantId, merchantApiV3Key), merchantApiV3Key.getBytes(StandardCharsets.UTF_8));
            //解析请求体
            Notification notification = handler.parse(requests);

            String decryptData = notification.getDecryptData();
            //解析
            JSONObject jsonObject = JSONObject.parseObject(decryptData);

            String refund_status = jsonObject.getString("refund_status");

            if (refund_status.equals("SUCCESS")) {
                //订单号
                String out_trade_no = jsonObject.getString("out_trade_no");
                //这里是处理业务逻辑
                //code 退款码请前往微信支付文档查询
                map.put("code", 200);
                map.put("out_trade_no", out_trade_no);
                map.put("message", "退款成功");
                return map;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put("code", "USER_ACCOUNT_ABNORMAL");
        map.put("message", "退款请求失败");
        return map;
    }

    /**
     * 生成并发送短信验证码
     */
    public boolean sendVerifyCode(String[] phoneNumber,String sysOrg) {
        try {
            // 1. 防刷检查：同一手机号1分钟内只能发送一次
             String lastSendTimeKey = "verify:send:time:" + phoneNumber[0];
           // String lastSendTimeKey = "verify:send:time:15878776250" ;
            String lastSendTime = redisTemplate.opsForValue().get(lastSendTimeKey);
            if (StringUtils.hasText(lastSendTime)) {
                long interval = System.currentTimeMillis() - Long.parseLong(lastSendTime);
                if (interval < ANTI_SPAM_MINUTES * 60 * 1000) {
                    return false; // 未超过防刷间隔，拒绝发送
                }
            }

            // 2. 生成6位随机验证码
            String verifyCode = generateVerifyCode(6);
            // 3. 发送短信（调用腾讯云接口）
           boolean b = SendSmsUtil.sendMsg(phoneNumber, new String[]{verifyCode,EXPIRE_MINUTES+""},sysOrg);

            // 4. 存储验证码到Redis（手机号为key，验证码为value）
          String verifyCodeKey = "verify:code:" + phoneNumber[0];
           redisTemplate.opsForValue().set(verifyCodeKey, verifyCode, EXPIRE_MINUTES, TimeUnit.MINUTES);

            // 5. 记录发送时间，用于防刷
           redisTemplate.opsForValue().set(lastSendTimeKey,
                  String.valueOf(System.currentTimeMillis()),
                   ANTI_SPAM_MINUTES, TimeUnit.MINUTES);

            return b;
        } catch (Exception e) {
            // 短信发送异常处理
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 验证短信验证码
     */
    public boolean fnverifyCode(String phoneNumber, String inputCode,String openId) {
        if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(inputCode)) {
            return false;
        }

        // 从Redis获取验证码
        String verifyCodeKey = "verify:code:" + phoneNumber;
        String storedCode = redisTemplate.opsForValue().get(verifyCodeKey);

        // 验证逻辑
        if (StringUtils.hasText(storedCode) && storedCode.equals(inputCode)) {
            // 验证成功后删除验证码，防止重复使用
            redisTemplate.delete(verifyCodeKey);

            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();

            // 获取HttpServletRequest
            HttpServletRequest request = attributes.getRequest();
            try {
                NurseUser nurseUser = nurseUserService.getOne(new QueryWrapper<NurseUser>().eq("openid", openId));
                if (oConvertUtils.isNotEmpty(nurseUser)) {
                    // 根据用户名查询用户信息
                    nurseUser.setPhone(phoneNumber);
                    nurseUser.setIsPhone("1");
                    nurseUserService.updateById(nurseUser);
                }

            } catch (Exception e) {
                log.warn("SecurityUtils.getSubject() 更新用户手机异常：" + e.getMessage());
                return false;
            }
            return true;
        }
        return false;
    }

    /**
     * 生成指定长度的随机数字验证码
     */
    private String generateVerifyCode(int length) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < length; i++) {
            code.append(random.nextInt(10)); // 生成0-9的随机数
        }
        return code.toString();
    }

}